package com.bst.etl.service.impl;

import com.bst.common.core.domain.AjaxResult;
import com.bst.common.vo.HeaderAndBodyVO;
import com.bst.etl.service.IEtlQryDmPubChartService;
import com.bst.etl.service.IEtlQryDmPubService;
import com.bst.etl.utils.IndexQueryUtil;
import com.bst.etl.vo.chart.ChartResultVO;
import com.bst.etl.vo.chart.ChartStyleVO;
import com.bst.etl.vo.chart.ChartXVO;
import com.bst.etl.vo.chart.ChartYVO;
import com.bst.md.service.IMdMedDimService;
import com.bst.md.service.IMdMedPubfldService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

@Service
public class EtlQryDmPubChartServiceImpl implements IEtlQryDmPubChartService {

    @Resource
    IEtlQryDmPubService etlQryDmPubService;
    @Autowired
    IMdMedDimService mdMedDimService;
    @Autowired
    IMdMedPubfldService mdMedPubfldService;


    @Override
    public AjaxResult generateBaseShape(HeaderAndBodyVO headerAndBodyVO, ChartStyleVO styleVO) {
        String shapeType = styleVO.getChartType();
        ChartResultVO queryVO = new ChartResultVO();
        queryVO.setShapeType(shapeType);
        Map<String,String> header = headerAndBodyVO.getThead();
        if(header==null && !"table".equals(shapeType)) {
            queryVO.setData("{\"title\":{\"text\":\""+styleVO.getTitle()+"\"}}");
            return AjaxResult.success(queryVO);
        } else if(header==null && "table".equals(shapeType)) {
            queryVO.setData(new HeaderAndBodyVO());
            return AjaxResult.success(queryVO);
        }
        if("table".equals(shapeType)) {
            List<String> fields = styleVO.getShowFlds();
            if(fields!=null && fields.size()>0) {
                Map<String,String> newHeader = new LinkedHashMap();
                for (String field : fields) {
                    if(header.get(field)!=null) {
                        newHeader.put(field,header.get(field));
                    }
                }
                headerAndBodyVO.setThead(newHeader);
                if(StringUtils.isNotEmpty(styleVO.getRowToColFld())) {
                    rowToCol(headerAndBodyVO,styleVO);
                }
            }
            queryVO.setData(headerAndBodyVO);
        } else {
            List<Map<String,Object>> dataList = headerAndBodyVO.getTbody();
            List<ChartYVO> yvoList = styleVO.getChartYVOList();
            ChartXVO xvo = styleVO.getChartXVO();
            Map<String, ChartYVO> yvoMap = null;
            StringBuffer mainBuffer = new StringBuffer("{title:{text:'"+styleVO.getTitle()+"'},");
            String radius="";
            if("center".equals(styleVO.getTitlePosition()) && ChartStyleVO.CHART_PIE.equals(shapeType)) {
                mainBuffer = new StringBuffer("{title:{text:'"+styleVO.getTitle()+"',x:'center',y:'center'},");
                radius="radius:['50%', '70%'],";
            }
            String legendPosition = styleVO.getLegendPosition();
            if(StringUtils.isNotEmpty(legendPosition)) {
                if("right".equals(styleVO.getLegendPosition())) {
                    mainBuffer.append("legend:{orient: 'vertical',right:10,top: 'center'},");
                } else {
                    mainBuffer.append("legend:{},");
                }
            }
            mainBuffer.append("tooltip:{trigger: 'item',valueFormatter:"+getFormatterFunction(null)+"},");
            if(ChartStyleVO.CHART_PIE.equals(shapeType)) { //饼图
                mainBuffer.append("series:{type: 'pie',"+radius+"data:[");
                ChartYVO yvo = yvoList.get(0);
                for(Map<String,Object> map: dataList) {
                    mainBuffer.append("{value:"+map.get(yvo.getFieldName())+",name:'"+map.get(xvo.getFieldName())+"'},");
                }
                mainBuffer.append("],itemStyle:{normal:{label:{show:true,formatter:"+getPieValueFormatter(null)+" }}}}");
            } else {
                String xData="data:[",yData;
                Map<String,String> yDataMap = new LinkedHashMap<>();
                String name,fieldName ;
                int i=0;
                for(ChartYVO yvo:yvoList) {
                    fieldName = yvo.getFieldName();
                    if(StringUtils.isEmpty(fieldName)) {
                        continue;
                    }
                    name = header.get(fieldName);
                    yData="[";
                    i++;
                    for(Map<String,Object> map: dataList) {
                        if(i==1) {
                            xData += ("'"+map.get(xvo.getFieldName()) + "',");
                        }
                        yData += IndexQueryUtil.dataHandler(map.get(yvo.getFieldName())) + ",";
                    }
                    yData += ("],itemStyle:{normal:{label:{show:true,formatter:"+getValueFormatterFunction(null,null)+" }}}");
                    yDataMap.put(name,"{name:'"+name+"',type:'"+(yvo.getChartType()==null?styleVO.getChartType():yvo.getChartType())+"',data:"+yData+"},");
                }
                mainBuffer.append("xAxis:{type: 'category',"+xData+"]");
                if(StringUtils.isNotEmpty(xvo.getAxisLabel())) {
                    mainBuffer.append(",axisLabel:{"+xvo.getAxisLabel()+"}");
                }
                mainBuffer.append("},");
                mainBuffer.append("yAxis:{type: 'value',axisLabel:{formatter:"+getFormatterFunction(null)+"}},");
                mainBuffer.append("series:[");
                for(Map.Entry<String,String> entry:yDataMap.entrySet()) {
                    mainBuffer.append(entry.getValue());
                }
                mainBuffer.append("]");
            }
            mainBuffer.append("}");
            queryVO.setData(mainBuffer);
        }
        return AjaxResult.success(queryVO);
    }

    private void rowToCol(HeaderAndBodyVO headerAndBodyVO, ChartStyleVO styleVO) {
        String field = styleVO.getRowToColFld();
        Boolean fgOrder = styleVO.getFgRowToColOrder();
        Boolean fgShowAll = styleVO.getFgRowToShowAll();
        List<Map<String,Object>> list = headerAndBodyVO.getTbody();
        Map<String,String> newHeader = new HashMap<>();
        newHeader.putAll(headerAndBodyVO.getThead());
        Map<String,String> header = headerAndBodyVO.getThead();
        header.remove(field);
        Map<String,Map<String,Object>> newDataMap = new HashMap<>();
        Map<String,Object> newData;
        String key,unique,idIndex = this.getRowToColIndex(newHeader);

        for(Map<String,Object> data:list) {
            key = data.get(field).toString();
            unique = getUniqueKey(data,field,newHeader);
            if((newData=newDataMap.get(unique))==null) {
                newData = data;
                newData.remove(field);
                newDataMap.put(unique,newData);
            }else {
                newData.put(idIndex, new BigDecimal(newData.get(idIndex)==null?"0":newData.get(idIndex).toString()).add(new BigDecimal(data.get(idIndex)==null?"0":data.get(idIndex).toString())));
            }
            newData.put(key,data.get(idIndex));
            if(header.get(key)==null) {
                header.put(key,key);
            }
        }
        /*if(fgOrder) {
            newHeader = sortRowToColHeader(field,header,fgShowAll);
            headerAndBodyVO.setThead(newHeader);
        }*/
        list = new ArrayList<>(newDataMap.values());
        headerAndBodyVO.setTbody(list);
    }

    /*private Map<String,String> sortRowToColHeader(String field,Map<String,String> header,Boolean fgShowAll) {
        if(field.startsWith("NA_")) {
            field = field.replace("NA_","ID_");
        }
        MdMedPubfld pubfld =mdMedPubfldService.selectMdMedPubfldByIdPubfld(field);
        if(pubfld==null || StringUtils.isEmpty(pubfld.getCdTbDim())) {
            return header;
        }
        List<DimDataVO> dimDataVOS = mdMedDimService.queryDimDataWithOrder(pubfld.getCdTbDim());
        List<String> dimList = dimDataVOS.stream().map(DimDataVO::getNa).collect(Collectors.toList());
        Map<String,String> other = new LinkedHashMap<>();
        Map<String,String> dim = new HashMap<>();
        for(Map.Entry<String,String> entry:header.entrySet()) {
            if(dimList.contains(entry.getKey())) {
                dim.put(entry.getKey(),entry.getValue());
            } else {
                other.put(entry.getKey(),entry.getValue());
            }
        }
        String value;
        for(String key:dimList) {
            if((value=dim.get(key))!=null) {
                other.put(key,value);
            } else {
                if(fgShowAll) {
                    other.put(key,key);
                }
            }
        }
        return other;
    }*/

    private String getRowToColIndex(Map<String,String> header) {
        String key,unique="";
        for(Map.Entry<String,String> entry:header.entrySet()) {
            key = entry.getKey();
            if(key.startsWith("IDX_")) {
                return key;
            }
        }
        return "";
    }

    private String getUniqueKey(Map<String,Object> data,String field,Map<String,String> header) {
        String key,unique="";
        for(Map.Entry<String,String> entry:header.entrySet()) {
            key = entry.getKey();
            if(key.startsWith("IDX_") || key.equals(field) || key.toUpperCase().startsWith("NA_") ) {
                continue;
            }
            unique+=data.get(key)+"_";
        }
        return unique;
    }

    private String getFormatterFunction(String unit) {
        if(StringUtils.isNotEmpty(unit)) {
            unit += "("+unit+")";
        } else {
            unit = "";
        }
        String formatter = "function (value, index) {" +
                "  if (value >= 100000000) {" +
                "return (value / 100000000).toFixed(2) + \"亿"+unit+"\";" +
                "  } else if (value >= 10000) {" +
                "return (value / 10000).toFixed(2) + \"万"+unit+"\";" +
                "  } else if (value >= 1000) {" +
                "return (value / 1000).toFixed(2) + \"千"+unit+"\";" +
                "  } else {" +
                "return value " +(StringUtils.isNotEmpty(unit)?"+"+unit:unit)+
                "  }" +
                "}";
        return formatter;
    }

    private String getValueFormatterFunction(String unit,String chartType) {
        if(StringUtils.isNotEmpty(unit)) {
            unit += "("+unit+")";
        } else {
            unit = "";
        }
        String value;
        if(ChartStyleVO.CHART_PIE.equals(chartType)){
            value = "params.data.value";
        } else {
            value = "params.data";
        }
        String formatter = "function (params) { let value="+value+";" +
                "  if (value >= 100000000) {" +
                "return (value / 100000000).toFixed(2) + \"亿"+unit+"\";" +
                "  } else if (value >= 10000) {" +
                "return (value / 10000).toFixed(2) + \"万"+unit+"\";" +
                "  } else if (value >= 1000) {" +
                "return (value / 1000).toFixed(2) + \"千"+unit+"\";" +
                "  } else {" +
                "return value " +(StringUtils.isNotEmpty(unit)?"+"+unit:unit)+
                "  }" +
                "}";
        return formatter;
    }

    private String getPieValueFormatter(String unit) {
        if(StringUtils.isNotEmpty(unit)) {
            unit += "("+unit+")";
        } else {
            unit = "";
        }
        String formatter = "function (params) { let value=params.data.value;let name=params.data.name;" +
                "  if (value >= 100000000) {" +
                "return name+' '+(value / 100000000).toFixed(2) + \"亿"+unit+"（\"+params.percent+'%）';" +
                "  } else if (value >= 10000) {" +
                "return name+' '+(value / 10000).toFixed(2) + \"万"+unit+"（\"+params.percent+'%）';" +
                "  } else if (value >= 1000) {" +
                "return name+' '+(value / 1000).toFixed(2) + \"千"+unit+"（\"+params.percent+'%）';" +
                "  } else {" +
                "return name+' '+value+'"+unit+"（'+params.percent+'%）'"+
                "  }" +
                "}";
        return formatter;
    }
}
